Repository navigation
fix: prevent disabled models from starting new training rounds - #305
robertocarlous merged 15 commits into
Conversation
|
Reviewed against CI on Claimed: both Verified — correct, and the tests are load-bearing: Claimed: in-flight rounds can still complete, settle and pay rewards. Verified — correct: Claimed: the auditor checks the registry-assigned ID, not the constructor's anticipated one. Verified — correct: the fixture deliberately deploys with constructor ID 1 while the registry assigns ID 0. The test asserts Claimed: contract-size gate passes. Verified — locally: Claimed: bundled ABIs match the build artifacts. Verified — exact: comparing Claimed: the CLI deploy supports the new constructor shapes. Verified — on a live anvil, with the real Foundry artifacts: I drove
Storage / upgrade safety: both task contracts are non-upgradeable. Docs: the decisions are recorded with a link to Abraham's comment, which I checked is the real comment ID. The 9 doc files consistently say "future GIs only, no abort, redeploy required, review wiring". Links are green in CI Docs. Observations:
Not independently re-verified: the full Every checkable claim held up, and the kill-switch tests demonstrably guard the change. The contract side is mergeable as-is. Before merge: land PR No. 261 first and rebase (the |
Files changed (31) — as of
|
| Field | Value |
|---|---|
| Change | Modified |
| Lines | +23/-3 |
| Diff (what exactly is in this PR) | Adds ITaskModelRegistry public immutable modelRegistry. The constructor takes a fourth argument, modelRegistry_, and reverts TA_InvalidAddress if it has no code. Adds validateGIStart(uint256 gi) external view onlyTaskCoordinator. Updates the depositRewards NatSpec. |
| Functionality — how & why | How: validateGIStart calls modelRegistry.getModelIdByTaskAuditor(address(this)) → TA_ModelNotRegistered if absent, then modelDisabled(registeredId) → TA_ModelDisabled(id), then giRewardPool[gi] == 0 → TC_GIRewardPoolNotFunded. A registry revert bubbles up (fails closed). Why: issue No. 224, decision 1 (Abraham): disabling a model must stop new GIs, and the check lives in the auditor to protect the coordinator's size headroom. |
Diff vs current develop HEAD |
None — untouched since merge-base. |
| Recommended merge proposal | Merged as-is. Break-then-fix: 5 of the 8 new kill-switch tests fail when the coordinator stops calling this; all 8 pass with it. Size 21,885 B. |
| Actual merge proposal | Soon |
| Pending proposal | Follow-up issue (not this PR): the registry wiring is self-attested. Any contract with code passes the constructor, and approveModel doesn't check modelRegistry() == address(this). Suggested first step: a dincli dinrep pre-approval check. |
| Local merge conflict | No |
| GitHub merge conflict | No |
foundry/src/DINTaskCoordinator.sol
| Field | Value |
|---|---|
| Change | Modified |
| Lines | +3/-2 |
| Diff (what exactly is in this PR) | In _startGI, replaces if (dinTaskAuditorContract.giRewardPool(_GI) == 0) revert TC_GIRewardPoolNotFunded(); with dinTaskAuditorContract.validateGIStart(_GI);, plus a comment. |
| Functionality — how & why | How: one STATICCALL after the state/index checks and before updatePassScore, GI++ and _setGIstate, shared by both startGI overloads. Why: routes the funded-pool check and the new registry checks through one auditor call, so the coordinator gains no registry wiring of its own (runtime 23,387 B, 1,189 B margin). |
Diff vs current develop HEAD |
None — untouched since merge-base. |
| Recommended merge proposal | Merged as-is. This line is what the break-then-fix toggled; see the verification comment. |
| Actual merge proposal | Soon |
| Pending proposal | None |
| Local merge conflict | No |
| GitHub merge conflict | No |
foundry/src/DINShared.sol, foundry/src/DINModelRegistry.sol
| Field | Value |
|---|---|
| Change | Modified |
| Lines | +13/-0, +2/-1 |
| Diff (what exactly is in this PR) | DINShared: the new ITaskModelRegistry interface (two view functions), validateGIStart added to IDINTaskAuditor (as view), and the errors TA_ModelNotRegistered and TA_ModelDisabled(uint256). DINModelRegistry: disableModel NatSpec only. |
| Functionality — how & why | How: interfaces/errors only, no storage. The registry's existing getModelIdByTaskAuditor and public modelDisabled getter are what the auditor reads. Why: lets the auditor read the registry without importing it, and corrects the disableModel doc to the new scope. No storage-layout change to the upgradeable registry. |
Diff vs current develop HEAD |
None — untouched since merge-base. |
| Recommended merge proposal | Merged as-is. |
| Actual merge proposal | Soon |
| Pending proposal | None |
| Local merge conflict | No |
| GitHub merge conflict | No |
dincli/cli/modelownerd/deploy.py
| Field | Value |
|---|---|
| Change | Modified |
| Lines | +55/-8 |
| Diff (what exactly is in this PR) | New _task_constructor_args maps the artifact's constructor input types to arguments. It accepts coordinator (address)/(address,uint256) and auditor (address,address)/(…,uint256)/(…,uint256,address), and rejects anything else. Adds --model-id to both commands. A missing stake address is now a BadParameter (previously an UnboundLocalError). The auditor checks the paired coordinator's modelId() against --model-id before deploying, and takes the registry from din_info[network]["registry"]. |
| Functionality — how & why | How: constructor arguments are derived from the ABI, so Foundry and legacy Hardhat artifacts both deploy, and every mismatch fails before any tx. Why: develop's CLI passed one argument to the two-argument coordinator (unusable with current artifacts), and the new auditor needs the canonical registry. |
Diff vs current develop HEAD |
None — untouched since merge-base. |
| Recommended merge proposal | Needs a rebase after PR No. 261 (conflict in this file; both rewrite constructor wiring), then one small fix: wrap the paired modelId().call() in try/except and raise BadParameter. Today a coordinator without modelId() gives a raw ContractLogicError: execution reverted (reproduced on anvil). All other paths were verified live on anvil with the real Foundry artifacts. |
| Actual merge proposal | Soon |
| Pending proposal | Merge order: No. 261 first, then the author rebases and re-runs (as offered in the PR body). The try/except fix can go in that same rebase. |
| Local merge conflict | No (against develop); Yes against PR No. 261's head |
| GitHub merge conflict | No |
dincli/abis/DINTaskAuditor.json, dincli/abis/DINTaskCoordinator.json
| Field | Value |
|---|---|
| Change | Modified |
| Lines | +52/-0, +0/-5 |
| Diff (what exactly is in this PR) | Regenerated: the auditor gains modelRegistry, validateGIStart, the fourth constructor input and the two new errors. The coordinator loses TC_GIRewardPoolNotFunded, which is now raised by the auditor. |
| Functionality — how & why | How: bundled ABIs are the fallback when a manifest gives no custom task_contracts ABI. Why: they must match what forge build emits. |
Diff vs current develop HEAD |
None — untouched since merge-base. |
| Recommended merge proposal | Merged as-is (or regenerated after the No. 261 rebase). Sorted-JSON comparison with foundry/out: identical (160/160, 201/201 entries). |
| Actual merge proposal | Soon |
| Pending proposal | cache_model_0/abis/ isn't refreshed here; PR No. 261 does that. Re-check after the rebase. |
| Local merge conflict | No |
| GitHub merge conflict | No |
tests/test_model_disable_deployment.py
| Field | Value |
|---|---|
| Change | New |
| Lines | +75/-0 |
| Diff (what exactly is in this PR) | Parametrised tests of _task_constructor_args (supported shapes, --model-id range, missing registry, unknown signatures), plus one command-level test of task_auditor with mocks: canonical registry passed, two txs sent, and on mismatch no constructor call and no tx. |
| Functionality — how & why | How: no chain or wallet. Why: pins the ABI-shape mapping and the pair check. |
Diff vs current develop HEAD |
None — file doesn't exist on develop. |
| Recommended merge proposal | Merged as-is: 13 passed locally and green in CI Python. If the try/except fix is applied, add one case for a coordinator whose modelId() reverts. |
| Actual merge proposal | Soon |
| Pending proposal | None |
| Local merge conflict | No |
| GitHub merge conflict | No |
foundry/test/RewardEngine.t.sol
| Field | Value |
|---|---|
| Change | Modified |
| Lines | +143/-3 |
| Diff (what exactly is in this PR) | The task-pair fixture now deploys against the real registry proxy, registers and approves the model (ID 0, against constructor ID 1), with optional skipRegistration / disableDuringGI flags. Adds 8 tests: both overloads disabled plus atomicity plus re-enable, private funding after disable, unregistered, registry-read failure (mockCallRevert), zero/EOA wiring, wrong registry contract, onlyTaskCoordinator, and in-flight GI completes/settles/claims but the next GI is blocked. |
| Functionality — how & why | How: integration against the real DINModelRegistry, not a stub. The atomicity test compares the params() bytes and the GI/GIstate before and after a failed start. Why: covers every branch of validateGIStart and the "no abort" in-flight guarantee. |
Diff vs current develop HEAD |
None — untouched since merge-base. |
| Recommended merge proposal | Merged as-is. 8/8 pass; break-then-fix turns 5 red without the coordinator call. |
| Actual merge proposal | Soon |
| Pending proposal | None |
| Local merge conflict | No |
| GitHub merge conflict | No |
foundry/test/utils/EnabledModelRegistry.sol + constructor updates in 12 test files
AggregatorCommitReveal, AuditorCommitReveal, DeployPlatform, DisputeResolution, EncryptedTestData, GasSimulation, LifecycleEvents, PR146SlashingRegression, ScoringValidation, SecurityFindings, StakingEnforcement, TreasuryForwarding (.t.sol)
| Field | Value |
|---|---|
| Change | New (1) / Modified (12) |
| Lines | +14/-0; +2/-1 each (SecurityFindings +6/-3, StakingEnforcement +3/-2) |
| Diff (what exactly is in this PR) | A stub registry that always returns (true, 0) and not-disabled. Each existing new DINTaskAuditor(…, id) gets a fourth argument, address(new EnabledModelRegistry()). |
| Functionality — how & why | How: keeps the isolated suites (which never register the model) startable under the new guard. Why: a mechanical update for the new constructor. The kill-switch semantics themselves are tested against the real registry in RewardEngine. |
Diff vs current develop HEAD |
None — untouched since merge-base. |
| Recommended merge proposal | Merged as-is. Full suite green in CI Solidity. Note that this stub is also a working example of the bypass described in observation 1 of the verification comment. |
| Actual merge proposal | Soon |
| Pending proposal | None |
| Local merge conflict | No |
| GitHub merge conflict | No |
Documentation (9 files)
public/roles/dinrep.md, public/workflows/model-workflow.md, technical/audits/foundry-src-security-review.md, technical/contracts/{DINModelRegistry,DINShared,DINTaskAuditor,DINTaskCoordinator,DinValidatorStake}.md, technical/mechanisms/staking-mechanism.md
| Field | Value |
|---|---|
| Change | Modified |
| Lines | +51/-28 in total |
| Diff (what exactly is in this PR) | Kill-switch scope (future GIs only, no abort or refund, redeploy required, the DIN-Representative reviews the wiring), the --model-id and din_info.registry deploy steps, the non-refundable registration fee (L-4 marked confirmed-intentional), S6 marked "parked for testnet", and M-2 in the audit doc marked resolved for new compatible pairs, with the original finding kept. |
| Functionality — how & why | How: each statement matches the code above. Decisions link to issue No. 224's decision comment. Why: decisions 2 and 3 of No. 224 are docs-only, and decision 1 changes documented behaviour. |
Diff vs current develop HEAD |
None — untouched since merge-base. |
| Recommended merge proposal | Merged as-is. Links are green in CI Docs. |
| Actual merge proposal | Soon |
| Pending proposal | If the dincli wiring check from observation 1 lands later, update the "DIN-Representative must review … registry address" sentences to point at it. |
| Local merge conflict | No |
| GitHub merge conflict | No |
Verification
CI on 2a9c546: CI OK green. The non-required Integration (full GI) job is red on the same pre-existing missing proxyAdmin assertion as develop. Locally (real via_ir profile, after npm ci): forge build --sizes, the 8 kill-switch tests (8/8), break-then-fix (5 red without the coordinator call), the ABI parity check, pytest tests/test_model_disable_deployment.py (13 passed), and a live anvil deploy of the real Foundry task pair through the PR's deploy.py commands. Full detail is in the verification comment above.
Approvals needed (MAINTAINING No. 4.2): foundry/src/** plus a mechanism decision: the peer approval (@umeradl) and @abrahamnash as the second key.
Local vs. GitHub agree: both clean against develop.
umeradl
left a comment
There was a problem hiding this comment.
Approved at 2a9c546 (first key; foundry/src and a mechanism decision, so @abrahamnash's approval is also required). Kill-switch tests verified by break-then-fix (5/8 fail without the coordinator call); coordinator size margin 1,189 B; ABIs match the build; deploy CLI exercised on anvil with real artifacts. Before merge: land PR No. 261 first and rebase (deploy.py conflict), and turn the raw ContractLogicError for a paired coordinator without modelId() into a BadParameter. Self-attested registry wiring goes to a follow-up issue (observation 1).
|
Thanks for the detailed review and deployment checks, @umeradl! Pushed the focused error handling in All 24 targeted deployment tests passed in an isolated environment, covering the failure paths, absence of deployment side effects, and legacy compatibility. I haven't rerun live deployment or full-GI tests. I'll keep this waiting for PR No. 261, then reconcile the deployment overlap and rerun the relevant checks. Abraham's requested sign-off remains outstanding, and I'll keep registry-wiring enforcement as a separate follow-up. Fresh CI and re-review of the new head are still needed. |
|
Reviewed against CI on Claimed — Claimed — Claimed — Claimed — Claimed — all three errors are file-level selectors, not contract-scoped. Verified: Claimed — 8 new kill-switch tests in Claimed — Claimed — Claimed — Claimed — security review M-2 updated with resolution. Verified in Claimed — Finding — P2: Merge state: branch is BEHIND develop (GitHub mergeStateStatus: BEHIND), no conflict (local merge-tree exit 0). Needs |
|
Head at review:
|
| Key | Value |
|---|---|
| Change | +12 lines: ITaskModelRegistry interface (getModelIdByTaskAuditor, modelDisabled); IDINTaskAuditor.validateGIStart declaration; TA_ModelNotRegistered and TA_ModelDisabled(uint256) errors |
| Pending proposal | None — interface matches real DINModelRegistry functions; errors declared at file level; selectors correct |
| Recommended merge proposal | Merge as-is |
| Actual merge proposal | Soon |
foundry/src/DINTaskAuditor.sol
| Key | Value |
|---|---|
| Change | +26 lines: ITaskModelRegistry public immutable modelRegistry; constructor gains 4th arg modelRegistry_ (non-EOA check); validateGIStart(uint256 gi) external view onlyTaskCoordinator checks registry approval + disabled + reward pool in order |
| Pending proposal | None — implementation correct; uses registry-returned ID (not constructor modelId); all errors from DINShared.sol |
| Recommended merge proposal | Merge as-is |
| Actual merge proposal | Soon |
foundry/src/DINTaskCoordinator.sol
| Key | Value |
|---|---|
| Change | -2/+2 lines: _startGI replaces direct giRewardPool check with dinTaskAuditorContract.validateGIStart(_GI) |
| Pending proposal | None — both public overloads call _startGI; call is unconditional before any state mutation |
| Recommended merge proposal | Merge as-is |
| Actual merge proposal | Soon |
foundry/test/utils/EnabledModelRegistry.sol (new)
| Key | Value |
|---|---|
| Change | +19 lines: test stub always returns (true, 0) / false — satisfies new 4-arg auditor constructor in all non-kill-switch tests |
| Pending proposal | None |
| Recommended merge proposal | Merge as-is |
| Actual merge proposal | Soon |
foundry/test/RewardEngine.t.sol
| Key | Value |
|---|---|
| Change | +130 lines: 8 new kill-switch tests; covers both startGI overloads blocked atomically, state unchanged, re-enable resumes; in-flight GI completes normally after disable but next GI blocked |
| Pending proposal | None |
| Recommended merge proposal | Merge as-is |
| Actual merge proposal | Soon |
foundry/test/SecurityFindings.t.sol
| Key | Value |
|---|---|
| Change | Constructor updates to pass the 4-arg auditor form |
| Pending proposal | None |
| Recommended merge proposal | Merge as-is |
| Actual merge proposal | Soon |
dincli/cli/modelownerd/deploy.py
| Key | Value |
|---|---|
| Change | _task_constructor_args helper added; handles 2/3-arg coordinator and 2/3/4-arg auditor constructors; --model-id option; reads registry from din_info; cross-checks --model-id against modelId() on the paired coordinator |
| Pending proposal | None |
| Recommended merge proposal | Merge as-is |
| Actual merge proposal | Soon |
dincli/abis/DINTaskAuditor.json
| Key | Value |
|---|---|
| Change | modelRegistry_ added to constructor inputs; modelRegistry view function; validateGIStart function; TA_ModelNotRegistered and TA_ModelDisabled errors |
| Pending proposal | None |
| Recommended merge proposal | Merge as-is |
| Actual merge proposal | Soon |
tests/test_model_disable_deployment.py (new)
| Key | Value |
|---|---|
| Change | +184 lines: constructor-shape tests, model-ID validation, registry requirement, mismatch rejection, full deploy flow with/without registry arg |
| Pending proposal | None |
| Recommended merge proposal | Merge as-is |
| Actual merge proposal | Soon |
Developer/BACK_LOG.md
| Key | Value |
|---|---|
| Change | BL-24 no additional change; BL-27 status clarified (more detail on PR No. 261 scope); BL-34 updated from "New — unaddressed" to "Decided, unimplemented — Abraham (Oct 26, No. 224)"; BL-35 updated from "New — unaddressed" to "Decided — keep as intended (Abraham, Oct 26)"; BL-28 status updated with more detail on planned command |
| Pending proposal | P2 BL-34 status should be "✅ Resolved" — this PR implements the decision. Replace the current BL-34 status with: ✅ Resolved — \validateGIStart` wired in `DINTaskAuditor.sol`; both `startGI` overloads check registry approval and disabled status via `_startGI`. Compatible task pairs required; existing deployed pairs unaffected. PR No. 305` |
| Recommended merge proposal | Update BL-34 to "✅ Resolved", then merge |
| Actual merge proposal | Soon |
Documentation/technical/audits/foundry-src-security-review.md
| Key | Value |
|---|---|
| Change | M-2 resolution paragraph added; L-4 confirmed intentional (BL-35); original finding text retained as audit context |
| Pending proposal | None |
| Recommended merge proposal | Merge as-is |
| Actual merge proposal | Soon |
Documentation/technical/contracts/DINTaskAuditor.md
| Key | Value |
|---|---|
| Change | modelRegistry (immutable) added to dependencies table; validateGIStart added to coordinator-only caller table; new "Future-GI guard and deployment" subsection covering constructor, guard semantics, disabling/reenabling, non-upgradeable caveat |
| Pending proposal | None |
| Recommended merge proposal | Merge as-is |
| Actual merge proposal | Soon |
Documentation/technical/contracts/DINTaskCoordinator.md, DINShared.md, DINModelRegistry.md, DinValidatorStake.md
| Key | Value |
|---|---|
| Change | Cross-references updated to mention validateGIStart call in _startGI; DINModelRegistry.md notes getModelIdByTaskAuditor is called by compatible task auditors |
| Pending proposal | None |
| Recommended merge proposal | Merge as-is |
| Actual merge proposal | Soon |
.github/workflows/ci.yml / .github/workflows/full-gi.yml (new)
| Key | Value |
|---|---|
| Change | integration-paths + integration jobs removed from ci.yml (-178 lines); equivalent integration job added to new full-gi.yml as workflow_dispatch only (manual trigger) |
| Pending proposal | None — ci-ok never depended on the integration job; this is a non-breaking extraction |
| Recommended merge proposal | Merge as-is |
| Actual merge proposal | Soon |
Remaining documentation files (skills, MAINTAINING.md, CONTRIBUTING.md, ROADMAP.md, role/workflow docs, README)
| Key | Value |
|---|---|
| Change | Cross-references, task-contract deployment steps, and skill descriptions updated to reflect the 4-arg auditor constructor and validateGIStart behavior |
| Pending proposal | None |
| Recommended merge proposal | Merge as-is |
| Actual merge proposal | Soon |
robertocarlous
left a comment
There was a problem hiding this comment.
P2-1: Developer/BACK_LOG.md BL-34 status should be updated to ✅ Resolved — this PR implements the fix. Please change the current "Decided, unimplemented" text to: "✅ Resolved — validateGIStart wired in DINTaskAuditor.sol; both startGI overloads check registry approval and disabled status via _startGI. Compatible task pairs required; existing deployed pairs unaffected. PR No. 305." Verified at 90a72422. Everything else — contracts, tests, CLI, ABIs, docs — is correct and merge-ready once this row is updated.
|
Thanks for the reviews and thorough checks! Fixed BL-34 in Only the backlog status changed. Diff checks and all 293 documentation-link checks passed. I’ll reconcile the deployment changes once PR No. 261 lands, then rerun the relevant checks and request a fresh review. |
|
Thanks for the thorough review! I’ve reconciled this branch with develop after PR No. 261 and pushed the updates through The CLI now checks the coordinator’s protocol version before deploying or pairing an auditor, rejecting incompatible combinations while preserving matching current and legacy pairs. The artifacts and docs are updated too. Local validation is green: 735 Python tests and 527 Foundry tests passed. Live CLI checks confirmed that all eight incompatible pairings reject without transactions or address writes. Astra also rechecked the fix and found no new issues. Fresh CI is running. Persistent IPFS publication and independent retrieval, along with fresh CI results and the required reviews, are still pending before this is ready to merge. The current IPFS evidence covers local offline pinning and retrieval only. |
|
Thanks again for the thorough reviews! PR #261 is now incorporated, the deployment changes are reconciled, and the earlier requested fixes are addressed. Latest CI is green: 527 Foundry tests and 895 Python tests passed, including artifact parity and contract-size checks. |
|
Reconciled PR #305 with the latest Fresh validation passed:
Fresh GitHub CI is queued. Passing CI and the required peer review/sign-offs remain before merge. |
|
Re-review of the fix commits: CI on What changed in the PR's own diff since Claimed: a revert reading the paired coordinator's Verified — fixed: Claimed: the CLI rejects incompatible coordinator/auditor generations before the one-shot pairing ( Verified — on a live anvil, with real artifacts: I drove dincli's own
Both rejected rows matter. Row 2 would brick the pair: the new coordinator calls Claimed: BL-34 is marked resolved ( Verified: the BL-34 status cell is now Robbert's suggested text, verbatim. BL-31 and BL-35 also record what this PR documents. Claimed: PR No. 261 is reconciled, and the reference-model artifacts and manifest CIDs are refreshed (my observation No. 4). Verified — exact: after a local Claimed: the two pinned remappings make the bytecode reproducible ( Verified, indirectly: with the pins in place, my local build matches the committed bytecode exactly, as above. Neither added remapping ( Claimed: contract-size gate passes. Verified — locally: Claimed: the kill-switch tests still guard the change, plus a new disabled-status read-failure test. Verified: Previous observations — status:
New observations (none blocking):
Not independently re-verified: the full Every new claim held up. The contract change since my approval is one pure getter, and the CLI generation check behaves correctly on a live chain in all four pairings. Mergeable as-is. New observations 1(a), 2 and 3 are small and can go in before merge or at merge; 1(b) and the exact-bytecode question can be a follow-up. My earlier approval was dismissed by the new commits; a fresh first-key approval follows separately. This touches |
Files changed (42) — as of
|
| Field | Value |
|---|---|
| Change | Modified (changed since 2a9c546) |
| Lines | +10/-2 |
| Diff (what exactly is in this PR) | The _startGI swap to dinTaskAuditorContract.validateGIStart(_GI) is unchanged. New: function taskProtocolVersion() external pure returns (uint256) { return 1; }. |
| Functionality — how & why | How: a constant getter with no storage, so there is no layout impact (the task contracts are non-upgradeable anyway). Why: deploy tooling needs to tell a guard-calling coordinator from a legacy one before the irreversible setDINTaskAuditorContract. Without it, a mismatched pair either bricks startGI or silently drops the kill switch. |
Diff vs current develop HEAD |
None (develop is the merge-base) |
| Recommended merge proposal | Merge as-is. 23,321 B runtime, 1,255 B margin (local contract_size_gate.py). |
| Actual merge proposal | Soon |
| Pending proposal | None |
| Local merge conflict | No |
| GitHub merge conflict | No |
dincli/cli/modelownerd/deploy.py
| Field | Value |
|---|---|
| Change | Modified (changed since 2a9c546) |
| Lines | +139/-53 |
| Diff (what exactly is in this PR) | Adds _task_constructor_signature (an allow-list of 2 coordinator and 3 auditor shapes) and _task_constructor_args. task-coordinator sets the DinToken and defaults --model-id only for the 2-arg coordinator. task-auditor wraps the modelId() read in a BadParameter, checks get_code, reads taskProtocolVersion() (absent → 0), rejects mismatched generations, and keeps the two legacy families apart. Drops the unused get_env_key import. |
| Functionality — how & why | How: all checks run before the first tx. The auditor's generation is inferred from its constructor arity (4 args → 1), and the coordinator must report the same value. Why: auditor pairing is one-shot. Verified on a live anvil in all four pairings (see the verification comment). |
Diff vs current develop HEAD |
None |
| Recommended merge proposal | Merge, ideally with new observation No. 2 first: move the w3.eth.get_code(task_coordinator_address) check above the modelId() read so an address without code gets the "no deployed code" message. Cosmetic: the import reshuffle dropped the blank line between typing and typer. |
| Actual merge proposal | Soon |
| Pending proposal | New observation No. 2 (non-blocking) |
| Local merge conflict | No |
| GitHub merge conflict | No |
.github/scripts/check_task_artifacts.py (new), .github/workflows/ci.yml, tests/test_task_artifact_check.py (new)
| Field | Value |
|---|---|
| Change | New script plus its tests; a 3-line CI step after forge build in the Solidity job |
| Lines | +101 / +3 / +133 |
| Diff (what exactly is in this PR) | Compares the canonical (order-insensitive) ABI of dincli/abis and cache_model_0/abis against foundry/out. Also requires cache_model_0 creation bytecode to equal the build exactly, and on mismatch prints diagnostics (first differing byte, lengths, sha256, compiler settings, source hashes). |
| Functionality — how & why | How: stdlib only; exits 1 with one line per drift. Why: this is the gate that stops the reference-model bundles going stale again (BL-25-style drift). Verified locally: passes on the committed files after a real via_ir build. |
Diff vs current develop HEAD |
None |
| Recommended merge proposal | Merge. Before merge or at merge: make the bytecode-mismatch message name the regen command, dincli system dump-abi --artifact foundry/out/<C>.sol/<C>.json --output cache_model_0/abis --bytecode, which I verified reproduces both committed files byte-for-byte (new observation No. 1(a)). |
| Actual merge proposal | Soon |
| Pending proposal | New observation No. 1(b), a manifest-CID check in the gate, which can be a follow-up. Whether cache_model_0 keeps exact-bytecode parity at all is a maintainer call. |
| Local merge conflict | No |
| GitHub merge conflict | No |
cache_model_0/abis/DINTaskCoordinator.json, cache_model_0/abis/DINTaskAuditor.json, cache_model_0/manifest.json
| Field | Value |
|---|---|
| Change | Modified (new to this PR since 2a9c546) |
| Lines | +20/-7, +58/-6, +3/-3 |
| Diff (what exactly is in this PR) | The ABI and creation bytecode are regenerated from the PR's build. The manifest's two ipfs CIDs move from bafybei… to raw CIDv1 bafkreigjv7cx… / bafkreidgp65w…, and a trailing newline is added. |
| Functionality — how & why | How: the reference model now deploys the guarded pair. Why: without this, model 0's bundled artifacts would deploy a coordinator that the auditor bundle can't pair with. |
Diff vs current develop HEAD |
None |
| Recommended merge proposal | Merge as-is. Bytecode is byte-identical to a local build; both CIDs recompute exactly from the committed files. |
| Actual merge proposal | Soon |
| Pending proposal | Author to confirm both CIDs are pinned (new observation No. 3); public gateways timed out for me |
| Local merge conflict | No |
| GitHub merge conflict | No |
dincli/abis/DINTaskCoordinator.json
| Field | Value |
|---|---|
| Change | Modified (changed since 2a9c546) |
| Lines | +13/-5 |
| Diff (what exactly is in this PR) | Adds taskProtocolVersion (pure). TC_GIRewardPoolNotFunded still leaves the coordinator ABI, as before. |
| Functionality — how & why | ABI parity with the build, now enforced by check_task_artifacts.py |
Diff vs current develop HEAD |
None |
| Recommended merge proposal | Merge as-is (gate passes locally) |
| Actual merge proposal | Soon |
| Pending proposal | None |
| Local merge conflict | No |
| GitHub merge conflict | No |
foundry/remappings.txt
| Field | Value |
|---|---|
| Change | Modified (new to this PR since 2a9c546) |
| Lines | +2/-0 |
| Diff (what exactly is in this PR) | Pins erc4626-tests/ and halmos-cheatcodes/ to the copies nested under openzeppelin-contracts-upgradeable/lib/ |
| Functionality — how & why | How: neither is imported by foundry/src. The pins only stop forge's auto-remapping choosing between duplicate nested libs per environment. Why: that choice changes the metadata hash, and therefore the bytecode the new gate compares exactly. |
Diff vs current develop HEAD |
None |
| Recommended merge proposal | Merge as-is. My local build reproduces CI's bytecode with these pins. |
| Actual merge proposal | Soon |
| Pending proposal | None |
| Local merge conflict | No |
| GitHub merge conflict | No |
foundry/test/RewardEngine.t.sol
| Field | Value |
|---|---|
| Change | Modified (changed since 2a9c546) |
| Lines | +161/-3 |
| Diff (what exactly is in this PR) | The 8 kill-switch tests are unchanged. New: test_disabledStatusReadFailure_failsClosed, and a taskProtocolVersion() == 1 assertion in test_registryWiring_rejectsZeroAndEOA. |
| Functionality — how & why | Covers a registry whose modelDisabled read reverts: startGI must fail closed, not open |
Diff vs current develop HEAD |
None |
| Recommended merge proposal | Merge as-is; 40/40 pass locally |
| Actual merge proposal | Soon |
| Pending proposal | None |
| Local merge conflict | No |
| GitHub merge conflict | No |
tests/test_model_disable_deployment.py, tests/test_deploy_task_contracts.py, tests/test_task_auditor_model_id_guard.py
| Field | Value |
|---|---|
| Change | Modified (the first changed since 2a9c546; the other two new to this PR since then) |
| Lines | +376/-0, +29/-4, +22/-16 |
| Diff (what exactly is in this PR) | The supported/unknown constructor shapes, invalid IDs, registry requirement, modelId() revert vs unrelated errors, the generation-mismatch matrix and the missing-version-getter paths. Each asserts no constructor/tx/.env/pairing side effect on rejection. The existing No. 261 tests are adapted to the new shapes. |
| Functionality — how & why | Mocked unit coverage of the same matrix I ran live on anvil |
Diff vs current develop HEAD |
None |
| Recommended merge proposal | Merge as-is (green in CI Python) |
| Actual merge proposal | Soon |
| Pending proposal | None |
| Local merge conflict | No |
| GitHub merge conflict | No |
Developer/BACK_LOG.md
| Field | Value |
|---|---|
| Change | Modified |
| Lines | +3/-3 |
| Diff (what exactly is in this PR) | BL-34 is now Robbert's suggested "✅ Resolved" text, verbatim. BL-31 gets a parked-behaviour note and BL-35 a "documented by PR No. 305" note. |
| Functionality — how & why | Closes Robbert's P2 |
Diff vs current develop HEAD |
None |
| Recommended merge proposal | Merge as-is |
| Actual merge proposal | Soon |
| Pending proposal | None |
| Local merge conflict | No |
| GitHub merge conflict | No |
Documentation/public/workflows/model-workflow.md, Documentation/public/roles/model-owner.md, Documentation/technical/contracts/DINTaskAuditor.md, Documentation/technical/contracts/DINTaskCoordinator.md
| Field | Value |
|---|---|
| Change | Modified (2 changed since 2a9c546, 2 new to this PR since then) |
| Lines | +12/-3, +3/-3, +13/-2, +6/-3 |
| Diff (what exactly is in this PR) | Deploy examples now point at foundry/out artifacts with --model-id. Adds the taskProtocolVersion() and legacy-pair rules, the registry requirement in din_info.json, and a note that the cache-default-artifacts bootstrap CIDs are historical. |
| Functionality — how & why | Documents exactly what deploy.py enforces; matches the code as read |
Diff vs current develop HEAD |
None |
| Recommended merge proposal | Merge as-is (CI Docs green). The model-workflow.md paragraph is dense; splitting it into a short list would read better, but that's optional. |
| Actual merge proposal | Soon |
| Pending proposal | None |
| Local merge conflict | No |
| GitHub merge conflict | No |
Verification
See the re-review verification comment above: live-anvil pairing matrix (4 pairings plus the EOA case), local via_ir build with the artifact gate passing, RewardEngine 40/40, the size gate, and the manifest CIDs recomputed. Everything else is from CI run 42274091689 on f46dd02.
Local vs. GitHub agree: yes, clean merge in both, branch up to date with develop.
umeradl
left a comment
There was a problem hiding this comment.
Approved at f46dd02 (first key; foundry/src and the No. 224 mechanism decision, so @abrahamnash's approval is also required). Since 2a9c546 the only contract change is the pure taskProtocolVersion() getter; coordinator 23,321 B (1,255 B margin). Deploy CLI generation check verified on live anvil across all four pairings plus a no-code address; bundled cache_model_0 bytecode reproduces byte-for-byte locally and both manifest CIDs recompute exactly. Non-blocking: regen command in the artifact-gate message, get_code check before the modelId() read, confirm the new CIDs are pinned.
3def72f
Actual outcome — PR #305 merged as-is (pushed)This supersedes the pre-merge review comment above with what actually happened. One commit on
No deviation commit was needed. Sign-offs: @robertocarlous as peer (approved at Files unchanged from the PR (42 of 42)
Not done before merge (follow-ups)The non-blocking observations from the re-review weren't applied before merge (the head stayed at
Issue No. 224 goes through VerificationThe merge-queue run on the merge-group commit and the post-merge push run on Local vs. GitHub agree: clean merge, as both predicted. |
Addresses issue #224 based on the decisions in this discussion.
startGIoverloads reject unregistered or disabled models, including when their reward pools are already funded.The auditor checks the registry-assigned model ID through immutable registry wiring. CLI constructor support and bundled ABIs are updated. In-flight rounds can still complete, settle and pay rewards.
Protection requires a newly deployed compatible coordinator/auditor pair wired to the canonical registry. Existing deployments are unchanged. No GI-abort or pool-refund mechanism is added.
Validation:
PR #261 should land first. The deployment CLI changes overlap, so this branch will need reconciliation after #261 lands. I’ll update it and rerun the relevant checks then.